#include"../../inc/local/MyDict.h"
#include <vector>
#include <string>
#include <map>
#include <set>
#include <iostream>
#include <fstream>

#include <sstream>
using std::ifstream;
using std::ofstream;
using std::stringstream;
using std::map;
using std::pair;
using std::set;
using std::string;
using std::vector;


namespace SC
{
    MyDict* MyDict::getpInstance()
    {
        return _pInstance;
    }

    void MyDict::destroy()
    {
        if(_pInstance)
        {
            delete _pInstance;
            _pInstance = nullptr;
        }
    }

    void MyDict::query(const string& queryWord, priority_queue<MyResult, vector<MyResult>, MyCompare> &priQueue)
    {
        set<int> myset;
        vector<string> singlechar = divide(queryWord);

        for(auto & c : singlechar)
        {
            if(_indexMap.find(c) != _indexMap.end())
            {
                set<int> temp = _indexMap[c];
                for(auto & i : temp)
                    myset.insert(i);
            }
        }

        for(auto i : myset)
        {
            string word = _dict[i].first;
            int frequency = _dict[i].second;
            int distance = editDistance(queryWord, word);
            MyResult res(word, frequency, distance);
            priQueue.push(res);
        }
    }

    void MyDict::initDict(const string &en_dir, const string &ch_dir, const string &en_dict_path, const string &ch_dict_path, const string &cache_dir)
    {
        SplitToolCppJieba split;
        DictProducer dictproducer(en_dir, ch_dir, en_dict_path, ch_dict_path, &split);
        unordered_map<string, int> dict = dictproducer.getDict();
        vector<pair<string, int>> temp(dict.begin(), dict.end());
        swap(temp, _dict);
        writeToCache(cache_dir);
        
        for(size_t i = 0; i < _dict.size(); i++)
        {
            vector<string> singleword = divide(_dict[i].first);
            for(auto & k : singleword)
                _indexMap[k].insert(i);
        }
    }

    void MyDict::initDict(const string& cache_dir)
    {
        _dict.resize(0);
        _indexMap.erase(_indexMap.begin(), _indexMap.end());

        readFromCache(cache_dir);

        for(size_t i = 0; i < _dict.size(); i++)
        {
            vector<string> singleword = divide(_dict[i].first);
            for(auto & k : singleword)
                _indexMap[k].insert(i);
        }
    }

    vector<string> MyDict::divide(const string& str)
    {
        vector<string> res;
        string mystr;
        for(int i = 0; str[i] != '\0';)
        {
            char c = str[i];
             //chr是0xxx xxxx
            if ((c & 0x80) == 0)
            {
                mystr = str.substr(i, 1);
                res.push_back(mystr);
                ++i;
            } //chr是1111 1xxx
            else if ((c & 0xF8) == 0xF8)
            {
                mystr = str.substr(i, 5);
                res.push_back(mystr);
                i += 5;
            } //chr是1111 xxxx
            else if ((c & 0xF0) == 0xF0)
            {
                mystr = str.substr(i, 4);
                res.push_back(mystr);
                i += 4;
            } //chr是111x xxxx
            else if ((c & 0xE0) == 0xE0)
            {
                mystr = str.substr(i, 3);
                res.push_back(mystr);
                i += 3;
            } //chr是11xx xxxx
            else if ((c & 0xC0) == 0xC0)
            {
                mystr = str.substr(i, 2);
                res.push_back(mystr);
                i += 2;
            }
        }
        return res;
    }

    void MyDict::writeToCache(const string& file)
    {
            ofstream ofs(file, ofstream::in);
            if(!ofs.good())
            {
                logError("openfile Err");
                exit(1);
            }

            for(auto & k : _dict)
            {
                ofs << k.first << " " << k.second << std::endl;
            }

            ofs.close();
    }

    void MyDict::readFromCache(const string& file)
    {
        ifstream ifs(file, ifstream::out);
        if(!ifs.good())
        {
            logError("openfile Err");
            exit(1);
        }

        string lines;
        string first;
        int second;

        while(getline(ifs, lines))
        {
            stringstream ss(lines);
            ss >> first >> second;
            _dict.push_back(std::make_pair(first, second));
        }

        ifs.close();
    }

    int MyDict::editDistance(const string& str1, const string& str2)
    {
        int len1 = str1.size();
        int len2 = str2.size();
        
        int **d = new int* [len1+1];
        for(int i = 0; i <= len1; i++)
            d[i] = new int[len2+1];

        int i, j;
        for(i = 0; i <= len1; i++)
            d[i][0] = i;
        for(j = 0; j <= len2; j++)
            d[0][j] = j;
        for(i = 1; i <= len1; i++)
            for(j = 1; j <= len2; j++)
            {
                int c = str1[i] == str2[j] ? 0 : 1;
                int deletion = d[i-1][j];
                int insertion = d[i][j-1];
                int substitution = d[i-1][j-1] + c;
                d[i][j] = min(deletion, insertion, substitution);
            }

        int ret = d[len1][len2];
        for(int i = 0; i <= len1; i++)
        {
            delete[] d[i];
        }
        delete[] d;
        return ret;
    }

    int MyDict::min(int a, int b, int c)
    {
        int tmp = a < b ? a : b;
        return tmp < c ? tmp : c;
    }

} // namespace SC
